package com.dps.recommend.utils;

import com.alicloud.openservices.tablestore.SyncClient;
import com.dps.recommend.beans.DpsRequest;
import com.dps.recommend.beans.RecItemDps;
import com.google.common.collect.Lists;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * dps基础service类
 */
public class DpsBaseService {

    /**
     * 设置每一层返回体字段
     *
     * @param recItemDpsList
     * @param request
     * @return
     */
    protected <T extends RecItemDps> List<T> setOrigList(List<T> recItemDpsList, DpsRequest request) {
        return CommonUtils.setOrigList(recItemDpsList, request);
    }

    //===================================初始化init开始

    /**
     * 获取用户曝光的数据
     * userId=req.reqeust.userId(为空则req.reqeust.deviceId)
     * 规则1:day为null时,redisKey=prefix+userId
     * 规则2:day不为空时,redisKey=prefix+userId_day[0-day)
     *
     * @param req    请求
     * @param prefix 前缀
     * @param day    缓存多少天,不加侧传递null
     * @return
     */
    protected List<String> getRedisUserExposureItemId(DpsRequest req, String prefix, Integer day, StringRedisTemplate stringRedisTemplate) {
        return CommonUtils.getRedisUserExposureItemId(req, prefix, day, stringRedisTemplate);
    }

    /**
     * 获取用户的曝光从extMap
     *
     * @param req
     * @return
     */
    protected List<String> getDpsUserExposureItemId(DpsRequest dpsRequest) {
        return CommonUtils.getDpsUserExposureItemId(dpsRequest);
    }

    /**
     * 是否在曝光里
     *
     * @param req
     * @return
     */
    protected boolean isStayExposure(DpsRequest dpsRequest, String itemId) {
        Boolean isFilter = Boolean.FALSE;
        if (StringUtils.isEmpty(itemId)) {
            return isFilter;
        }
        List<String> exposure = this.getDpsUserExposureItemId(dpsRequest);
        return exposure.contains(itemId) ? Boolean.TRUE : isFilter;
    }


    //===================================召回recall开始

    /**
     * @param dpsRequest
     * @param pkValue        tableJson的keyName的值
     * @param tableName      表名
     * @param keyName        主键
     * @param itemIds        值
     * @param columJson      {"itemId":0} 将tablestore的以,分割后，^的第一个元素映射到itemId
     * @param targetClassObj
     * @param syncClient
     * @param env
     * @return
     */
    protected List getTableStoreItemList(DpsRequest dpsRequest, String pkValue, String tableName, String keyName, String itemIds, String columJson, Class targetClassObj, SyncClient syncClient, String env) {
        return CommonUtils.getTableStoreItemList(dpsRequest, pkValue, tableName, keyName, itemIds, columJson, targetClassObj, syncClient, env);
    }

    /**
     * @param dpsRequest
     * @param pkValue        tableJson的keyName的值
     * @param tableName      表名
     * @param keyName        主键
     * @param itemIds        值
     * @param columJson      {"itemId":0} 将tablestore的以,分割后，^的第一个元素映射到itemId
     * @param targetClassObj
     * @param syncClient
     * @param env
     * @return
     */
    protected List getTableStoreItemList(DpsRequest dpsRequest, List<String> pkValue, String tableName, String keyName, String itemIds, String columJson, Class targetClassObj, SyncClient syncClient, String env) {
        return CommonUtils.getTableStoreItemList(dpsRequest, pkValue, tableName, keyName, itemIds, columJson, targetClassObj, syncClient, env);
    }


    /**
     * 调用tablestore返回的数据封装
     *
     * @param dpsRequest
     * @param pkValue        tableJson的keyName的值
     * @param tableJson      {"tableName":"hobby_subscribe_meta_info","keyName":"user_id","itemIds":"subscribe_label_ids"}
     * @param columJson      {"itemId":0} 将tablestore的以,分割后，^的第一个元素映射到itemId
     * @param targetClassObj
     * @param syncClient
     * @param env
     * @return
     */
    protected List getTableStoreItemList(DpsRequest dpsRequest, String pkValue, String tableJson, String columJson, Class targetClassObj, SyncClient syncClient, String env) {
        return CommonUtils.getTableStoreItemList(dpsRequest, pkValue, tableJson, columJson, targetClassObj, syncClient, env);
    }

    /**
     * 调用tablestore返回的数据封装
     *
     * @param dpsRequest
     * @param pkValue        tableJson的keyName的值
     * @param tableJson      {"tableName":"hobby_subscribe_meta_info","keyName":"user_id","itemIds":"subscribe_label_ids"}
     * @param columJson      {"itemId":0} 将tablestore的以,分割后，^的第一个元素映射到itemId
     * @param targetClassObj
     * @param syncClient
     * @param env
     * @return
     */
    protected List getTableStoreItemList(DpsRequest dpsRequest, List<String> pkValue, String tableJson, String columJson, Class targetClassObj, SyncClient syncClient, String env) {
        return CommonUtils.getTableStoreItemList(dpsRequest, pkValue, tableJson, columJson, targetClassObj, syncClient, env);
    }


    //===================================融合merage开始


    /**
     * 融合 根据itemId去重复并且取最高分数的数据，并且处理recallVersion为cn以,分割
     *
     * @param list
     * @return
     */
    protected <T extends RecItemDps> List<T> getMerageItemList(List<T> list) {
        return CommonUtils.getMerageItemList(list);
    }

    /**
     * 融合 根据itemId去重复并且取最高分数的数据
     *
     * @param list
     * @return
     */
    protected <T extends RecItemDps> List<T> getMerageTopScoreItemList(List<T> list) {
        return CommonUtils.getMerageTopScoreItemList(list);
    }


    /**
     * 融合 根据itemId和type去重复并且取最高分数的数据
     *
     * @param list
     * @return
     */
    protected <T extends RecItemDps> List<T> getMerageTopScoreItemTypeList(List<T> list) {
        return CommonUtils.getMerageTopScoreItemTypeList(list);
    }

    //===================================粗排widerank开始


    /**
     * 曝光过滤
     * userId=req.reqeust.userId(为空则req.reqeust.deviceId)
     * 规则1:day为null时,redisKey=prefix+userId
     * 规则2:day不为空时,redisKey=prefix+userId_day[0-day)
     *
     * @param req      请求
     * @param prefix   前缀
     * @param day      缓存多少天,不加侧传递null
     * @param newItems
     * @return
     */
    protected <T extends RecItemDps> List<T> filterRecItems(DpsRequest req, String prefix, Integer day, List<T> newItems, Map<String, Object> extMap, StringRedisTemplate stringRedisTemplate) {
        return CommonUtils.filterRecItems(req, prefix, day, CollectionUtils.isEmpty(newItems) ? Lists.newArrayList() : newItems, stringRedisTemplate, CollectionUtils.isEmpty(extMap) ? new HashMap<>() : extMap);
    }


    //===================================精排rank开始


    /**
     * 时间衰减 initScore*exp(-ratio*时间)
     *
     * @param createTime yyyy-MM-dd HH:mm:ss
     * @param initScore  初始化分数 默认=1.0
     * @param ratio      系数 默认=0.005
     * @return
     */
    protected double getTimeWeightScore(String createTime, Double initScore, Double ratio) {
        return CommonUtils.getTimeWeightScore(createTime, initScore, ratio);
    }

    /**
     * 根据类型(type字段)相邻打散、最大化保留顺序
     *
     * @param itemList
     * @param <T>
     * @return
     */
    protected <T extends RecItemDps> List<T> adjDisPer(DpsRequest dpsRequest, List<T> itemList, Integer num) {
        return DisperseUtils.adjDisPer(itemList, Objects.isNull(num) ? dpsRequest.getRequest().getPageSize() : num);
    }

    /**
     * 强制类型(type字段)轮询、最大化保留顺序、类型天然散列
     *
     * @param itemList
     * @param <T>
     * @return
     */
    protected <T extends RecItemDps> List<T> typeDisPer(DpsRequest dpsRequest, List<T> itemList, Integer num) {
        return DisperseUtils.typeDisPer(itemList, Objects.isNull(num) ? dpsRequest.getRequest().getPageSize() : num);
    }


    //===================================人工干预postrank开始


    /**
     * 添加假曝光
     * <p>
     * userId=req.reqeust.userId(为空则req.reqeust.deviceId)
     * 规则1:day为null时,redisKey=prefix+userId
     * 规则2:day不为空时,redisKey=prefix+userId_当天时间(yyyy-MM-dd)
     *
     * @param req
     * @param prefix           前缀
     * @param day              过期时间(天) 不传递侧为null
     * @param filterItemIdList
     */
    protected void saveUserImpression(DpsRequest req, String prefix, Integer day, String filterItemIdList, StringRedisTemplate stringRedisTemplate) {
        CommonUtils.saveUserImpression(req, prefix, day, filterItemIdList, stringRedisTemplate);
    }


    /**
     * 将source集合的数据赋值给target,并且忽视某些字段
     *
     * @param source         源List
     * @param target         目标List
     * @param targetClassObj 目标对象类型
     * @param ignoreArr      忽视某些字段
     */
    protected void copyList(List source, List target, Class targetClassObj, String[] ignoreArr) {
        CommonUtils.copyList(source, target, targetClassObj, ignoreArr);
    }

    /**
     * 将source集合的数据赋值给target,并且忽视某些字段
     *
     * @param source    源List
     * @param target    目标List
     * @param ignoreArr 忽视某些字段
     */
    protected List copyList(DpsRequest dpsRequest, List source, List target, String[] ignoreArr) {
        return CommonUtils.copyList(dpsRequest, source, target, ignoreArr);
    }


}
